package com.changgou.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.changgou.seckill.dao.SeckillGoodsMapper;
import com.changgou.seckill.dao.SeckillOrderMapper;
import com.changgou.seckill.pojo.SeckillGoods;
import com.changgou.seckill.pojo.SeckillOrder;
import com.changgou.seckill.pojo.SeckillStatus;
import com.changgou.seckill.service.SeckillOrderService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/****
 * @Author:黑马训练营
 * @Description:SeckillOrder业务层接口实现类
 * @Date 未来/6/14 0:16
 *****/
@Service
public class SeckillOrderServiceImpl implements SeckillOrderService {

    @Autowired
    private SeckillOrderMapper seckillOrderMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    /***
     * 删除订单
     * @param username
     */
    @Override
    public void closeOrder(String username) {
        //获取订单状态  "SeckillGoods_"+DateUtil.data2str(dateMenu,DateUtil.PATTERN_YYYYMMDDHH);
        SeckillStatus seckillStatus = JSON.parseObject(stringRedisTemplate.boundValueOps("SeckillStatus_"+username).get(),SeckillStatus.class);

        //回滚数据
        //查询对应的商品
        SeckillGoods seckillGoods = (SeckillGoods) redisTemplate.boundHashOps("SeckillGoods_" + seckillStatus.getTime()).get(seckillStatus.getGoodsId());

        // seckillGoods->redis=null->MySQL(同步)->MySQL少了1个->+1  AND 同步到Redis
        if(seckillGoods==null){
            seckillGoods = seckillGoodsMapper.selectByPrimaryKey(seckillStatus.getGoodsId());
            seckillGoods.setStockCount(seckillGoods.getStockCount()+1);
            //同步到MySQL
            seckillGoodsMapper.updateByPrimaryKeySelective(seckillGoods);
        }
        //同步到Redis,由于有定时器，这里不建议写库存回滚w
        //redisTemplate.boundHashOps("SeckillGoods_" + seckillStatus.getTime()).put(seckillGoods.getId(),seckillGoods);

        //计数器、队列
        //redisTemplate.boundListOps("SeckillGoodsCountList_"+seckillGoods.getId()).leftPush(seckillGoods.getId());
        //redisTemplate.boundHashOps("SeckillGoodsCount").increment(seckillGoods.getId(),1);

        //删除订单
        redisTemplate.boundHashOps("SeckillOrder").delete(username);
    }

    /***
     * 修改订单状态
     */
    @Override
    public void updatePayStatus(String username, String transactionid) {
        //查询订单信息
        SeckillOrder order = (SeckillOrder) redisTemplate.boundHashOps("SeckillOrder").get(username);

        //完善订单信息
        order.setPayTime(new Date());   //支付时间
        order.setStatus("1");   //已支付
        order.setTransactionId(transactionid); //微信交易流水号

        //同步到MySQL中
        seckillOrderMapper.insertSelective(order);

        //Redis中删除订单
        redisTemplate.boundHashOps("SeckillOrder").delete(username);

        //用户状态更新
        clearSeckillStatus(username);
    }

    /***
     * 清理用户排队标示信息
     */
    public void clearSeckillStatus(String username){
        //排队标示清理
        redisTemplate.delete("UserQueueCount_" + username);
        //状态清理
        SeckillStatus seckillStatus = JSON.parseObject(stringRedisTemplate.boundValueOps("SeckillStatus_" + username).get(),SeckillStatus.class);
        seckillStatus.setStatus(4); //支付完成
        stringRedisTemplate.boundValueOps("SeckillStatus_" + username).set(JSON.toJSONString(seckillStatus),1, TimeUnit.MINUTES);
    }

    /***
     * 秒杀抢单
     * @param username : 抢单用户
     * @param id : 商品ID
     * @param time : 时间 20200106
     */
    @Override
    public Boolean add(String username, String id, String time) {
        /***
         * boundValueOps("UserQueueCount_"+username).increment(N)
         * key的值递增N
         * 如果该key的值不存在，则表示初始值为9
         */
        //在Redis中定义一个变量 UserQueueCount_username,用户每次进入该方法，都让它的值递增1
        //第一次请求抢单UserQueueCount_username=1
        //返回值：递增之后的结果
        Long increment = redisTemplate.boundValueOps("UserQueueCount_" + username).increment(1);

        if(increment>1){
            //正在排队  100表示重复抢单
            throw new RuntimeException("100");
            //return true;
        }

        //封装抢单信息
        SeckillStatus seckillStatus = new SeckillStatus();
        seckillStatus.setUsername(username);
        seckillStatus.setCreateTime(new Date());
        seckillStatus.setStatus(1);     //排队中
        seckillStatus.setGoodsId(id);   //商品ID
        seckillStatus.setTime(time);    //商品所在的key的时间后缀

        //状态信息
        String statusJson = JSON.toJSONString(seckillStatus);

        //队列削峰
        //将抢单信息发送到RabbitMQ    交换机、队列、队列与交换机绑定
        rabbitTemplate.convertAndSend("seckillOrderExchange", "seckillOrderQueue",statusJson);

        //将抢单信息存入到Redis  key:value
        //                       key=SeckillStatus_username
        //                       value=seckillStatus
        String key = "SeckillStatus_"+username;
        stringRedisTemplate.boundValueOps(key).set(statusJson);
        return true;
    }

    /**
     * SeckillOrder条件+分页查询
     * @param seckillOrder 查询条件
     * @param page 页码
     * @param size 页大小
     * @return 分页结果
     */
    @Override
    public PageInfo<SeckillOrder> findPage(SeckillOrder seckillOrder, int page, int size){
        //分页
        PageHelper.startPage(page,size);
        //搜索条件构建
        Example example = createExample(seckillOrder);
        //执行搜索
        return new PageInfo<SeckillOrder>(seckillOrderMapper.selectByExample(example));
    }

    /**
     * SeckillOrder分页查询
     * @param page
     * @param size
     * @return
     */
    @Override
    public PageInfo<SeckillOrder> findPage(int page, int size){
        //静态分页
        PageHelper.startPage(page,size);
        //分页查询
        return new PageInfo<SeckillOrder>(seckillOrderMapper.selectAll());
    }

    /**
     * SeckillOrder条件查询
     * @param seckillOrder
     * @return
     */
    @Override
    public List<SeckillOrder> findList(SeckillOrder seckillOrder){
        //构建查询条件
        Example example = createExample(seckillOrder);
        //根据构建的条件查询数据
        return seckillOrderMapper.selectByExample(example);
    }


    /**
     * SeckillOrder构建查询对象
     * @param seckillOrder
     * @return
     */
    public Example createExample(SeckillOrder seckillOrder){
        Example example=new Example(SeckillOrder.class);
        Example.Criteria criteria = example.createCriteria();
        if(seckillOrder!=null){
            // 主键
            if(!StringUtils.isEmpty(seckillOrder.getId())){
                    criteria.andEqualTo("id",seckillOrder.getId());
            }
            // 秒杀商品ID
            if(!StringUtils.isEmpty(seckillOrder.getSeckillId())){
                    criteria.andEqualTo("seckillId",seckillOrder.getSeckillId());
            }
            // 支付金额
            if(!StringUtils.isEmpty(seckillOrder.getMoney())){
                    criteria.andEqualTo("money",seckillOrder.getMoney());
            }
            // 用户
            if(!StringUtils.isEmpty(seckillOrder.getUserId())){
                    criteria.andEqualTo("userId",seckillOrder.getUserId());
            }
            // 创建时间
            if(!StringUtils.isEmpty(seckillOrder.getCreateTime())){
                    criteria.andEqualTo("createTime",seckillOrder.getCreateTime());
            }
            // 支付时间
            if(!StringUtils.isEmpty(seckillOrder.getPayTime())){
                    criteria.andEqualTo("payTime",seckillOrder.getPayTime());
            }
            // 状态，0未支付，1已支付
            if(!StringUtils.isEmpty(seckillOrder.getStatus())){
                    criteria.andEqualTo("status",seckillOrder.getStatus());
            }
            // 收货人地址
            if(!StringUtils.isEmpty(seckillOrder.getReceiverAddress())){
                    criteria.andEqualTo("receiverAddress",seckillOrder.getReceiverAddress());
            }
            // 收货人电话
            if(!StringUtils.isEmpty(seckillOrder.getReceiverMobile())){
                    criteria.andEqualTo("receiverMobile",seckillOrder.getReceiverMobile());
            }
            // 收货人
            if(!StringUtils.isEmpty(seckillOrder.getReceiver())){
                    criteria.andEqualTo("receiver",seckillOrder.getReceiver());
            }
            // 交易流水
            if(!StringUtils.isEmpty(seckillOrder.getTransactionId())){
                    criteria.andEqualTo("transactionId",seckillOrder.getTransactionId());
            }
        }
        return example;
    }

    /**
     * 删除
     * @param id
     */
    @Override
    public void delete(String id){
        seckillOrderMapper.deleteByPrimaryKey(id);
    }

    /**
     * 修改SeckillOrder
     * @param seckillOrder
     */
    @Override
    public void update(SeckillOrder seckillOrder){
        seckillOrderMapper.updateByPrimaryKey(seckillOrder);
    }

    /**
     * 增加SeckillOrder
     * @param seckillOrder
     */
    @Override
    public void add(SeckillOrder seckillOrder){
        seckillOrderMapper.insert(seckillOrder);
    }

    /**
     * 根据ID查询SeckillOrder
     * @param id
     * @return
     */
    @Override
    public SeckillOrder findById(String id){
        return  seckillOrderMapper.selectByPrimaryKey(id);
    }

    /**
     * 查询SeckillOrder全部数据
     * @return
     */
    @Override
    public List<SeckillOrder> findAll() {
        return seckillOrderMapper.selectAll();
    }
}
